/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-07-24     Tanek        the first version
 * 2018-11-12     Ernest Chen  modify copyright
 */

#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include <bsp_usart.h>
#include <bsp_led.h>
#include <board.h>

extern __IO uint32_t uwTick;
static uint32_t _systick_ms = 1;

/* RT-Thread board init */
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE (1024 * 8)
static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    rt_kprintf("error handler\n");
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;

void SystemClock_Config(void) /* config system clock, AHB1/2/3/4, APB1/2/3/4... */
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    /** Initializes the CPU, AHB and APB busses clocks
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    /** Initializes the CPU, AHB and APB busses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
}

/* SysTick configuration */
void rt_hw_systick_init(void)
{
    HAL_SYSTICK_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

    _systick_ms = 1000u / RT_TICK_PER_SECOND;
    if (_systick_ms == 0)
        _systick_ms = 1;
}

/**
 * This function will initial your board.
 */
void rt_hw_board_init()
{
    HAL_Init();

    /* enable interrupt */
    __set_PRIMASK(0);
    /* System clock initialization */
    SystemClock_Config();
    /* disbale interrupt */
    __set_PRIMASK(1);

    rt_hw_systick_init();

    /* user init */
    bsp_led_init();
    bsp_debug_uart_init();

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)
        HAL_IncTick();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

#define DBG_TAG "board"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

int clock_information(void)
{
    LOG_I("System Clock information");
    LOG_I("SYSCLK_Frequency = %d", HAL_RCC_GetSysClockFreq());
    LOG_I("HCLK_Frequency   = %d", HAL_RCC_GetHCLKFreq());
    LOG_I("PCLK1_Frequency  = %d", HAL_RCC_GetPCLK1Freq());
    LOG_I("PCLK2_Frequency  = %d", HAL_RCC_GetPCLK2Freq());

    return RT_EOK;
}
INIT_BOARD_EXPORT(clock_information);

// uint32_t HAL_GetTick(void)
// {
//     if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)
//         HAL_IncTick();

//     return uwTick;
// }

// void HAL_IncTick(void)
// {
//     uwTick += _systick_ms;
// }

// void HAL_SuspendTick(void)
// {
// }

// void HAL_ResumeTick(void)
// {
// }

// /**
//  * This function will delay for some us.
//  *
//  * @param us the delay time of us
//  */
// void rt_hw_us_delay(rt_uint32_t us)
// {
//     rt_uint32_t ticks;
//     rt_uint32_t told, tnow, tcnt = 0;
//     rt_uint32_t reload = SysTick->LOAD;

//     ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
//     told = SysTick->VAL;
//     while (1)
//     {
//         tnow = SysTick->VAL;
//         if (tnow != told)
//         {
//             if (tnow < told)
//             {
//                 tcnt += told - tnow;
//             }
//             else
//             {
//                 tcnt += reload - tnow + told;
//             }
//             told = tnow;
//             if (tcnt >= ticks)
//             {
//                 break;
//             }
//         }
//     }
// }

// void HAL_Delay(__IO uint32_t Delay)
// {
//     if (rt_thread_self())
//     {
//         rt_thread_mdelay(Delay);
//     }
//     else
//     {
//         for (rt_uint32_t count = 0; count < Delay; count++)
//         {
//             rt_hw_us_delay(1000);
//         }
//     }
// }

// /* re-implement tick interface for STM32 HAL */
// HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
// {
//     rt_hw_systick_init();

//     /* Return function status */
//     return HAL_OK;
// }

static char ascii_2_u8(char c)
{
    char ret = 1;

    if (c == '0')
        ret = 0;
    else if (c == '1')
        ret = 1;
    else if (c == '2')
        ret = 2;
    else if (c == '3')
        ret = 3;
    else if (c == '4')
        ret = 4;
    else if (c == '5')
        ret = 5;
    else if (c == '6')
        ret = 6;
    else if (c == '7')
        ret = 7;
    else if (c == '8')
        ret = 8;
    else if (c == '9')
        ret = 9;
    else if (c == '-')
        ret = -1;

    return ret;
}

int rt_atoi(const char *int_str, int *ret_val)
{
    if (!int_str)
    {
        return -1;
    }

    uint8_t ch_val = 0;
    int val = 0;
    int str_len = rt_strlen(int_str);
    for (int i = 0; i < str_len; i++)
    {
        ch_val = ascii_2_u8(int_str[i]);
        if (int_str[i] == '.')
            break;

        val *= 10;
        val += ch_val;
    }

    *ret_val = val;
    return 0;
}

int rt_atof(const char *float_str, float *float_val)
{
    char ch_val = 0;
    int int_val = 0;
    int str_len = rt_strlen(float_str);
    float float_part_val = 0;

    for (int i = 0; i < str_len; i++)
    {
        ch_val = ascii_2_u8(float_str[i]);
        if (float_str[i] == '.')
        {
            /* 计算得到小数点后部分 */
            for (int j = i + 1; j < str_len; j++)
            {
                ch_val = ascii_2_u8(float_str[j]);
                float_part_val *= 10;
                float_part_val += ch_val;
            }
            break;
        }

        int_val *= 10;
        int_val += ch_val;
    }

    while (float_part_val > 1)
    {
        float_part_val *= 0.1f;
    }

    float_part_val += int_val;
    *float_val = float_part_val;

    return 0;
}
